package org.reborn.demo

import org.reborn.engine.app._
import org.reborn.engine.render._

import scala.math
import scala.List

import org.reborn.engine.model.mesh.{Mesh,MutableMesh,VertexData,MeshUtil,MeshConnectivity,MeshShapes}
import org.reborn.engine.enums.ArrayType
import org.reborn.engine.enums.FaceMode
import org.reborn.engine.enums.UpdateFrequency

import org.reborn.utils.HeightMapUtil._
import org.reborn.engine.render.util._
import org.reborn.utils.Util._
import org.reborn.Constants._

import java.awt._
import java.awt.event._;

import javax.media.opengl._
import javax.media.opengl.GL
import javax.media.opengl.fixedfunc.GLLightingFunc
import javax.media.opengl.glu._
import com.jogamp.opengl.util._
import com.jogamp.opengl.util.awt.TextRenderer

import GL._
import GLLightingFunc._

/*
 * This application creates a heightmap based on the diamond-squares
 * algorithm and then calculates per-vertex normals.
 * 
 * The heightmap is rendered using VBOs or a fallback if VBOs are not
 * supported by hardware.
 */
object HeightMapNormals extends GLApp {
  
  def main(args:Array[String]){
	
	//Set up some application options 
    val options = new GLAppOptions()
    options.title = "Normal Generation Test"
    //options.fullscreen = false
    options.debugGL = true
    
    //start the application
	startApp(options)
  }

  //Set up the variables we are going to use 
  var dt = 0.0f;
  var dRot = 0.0f
  val text = new TextRenderer(new Font("SansSerif", Font.BOLD, 20))
  
  var meshId = -1;
  
  var fpsAvg = 0.0f;
  
  override def initScene(drawable:GLAutoDrawable){
    val gl = drawable.getGL.getGL2
    import gl._
    
    //Set some OpenGL properties
    glEnable(GL_DEPTH_TEST)
    glDepthFunc(GL_LEQUAL)
    glHint(GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST)
    glClearColor(0.3f,0.3f,0.3f,1.0f)
    
    //Enable lighting
    glEnable(GL_LIGHTING)
    glShadeModel(GL_SMOOTH);
    glEnable(GL_COLOR_MATERIAL)
    glEnable(GL_LIGHT0)
    
    glLightfv(GL_LIGHT0,GL_POSITION,Array(0.0f,-1.0f,0.5f,0.0f),0)
    glLightfv(GL_LIGHT0,GL_AMBIENT,Array(0.3f,0.3f,0.3f,1.0f),0)
    glLightfv(GL_LIGHT0,GL_DIFFUSE,Array(1.0f,1.0f,1.0f,1.0f),0)
    glLightfv(GL_LIGHT0,GL_SPECULAR,Array(1.0f,1.0f,1.0f,1.0f),0)
    
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
    glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,Array(1.0f,1.0f,1.0f,1.0f),0)
    glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,Array(0.0f,0.0f,0.0f,0.0f),0)
    glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,40.0f)
    
    val maxHeight = 1.0f
    
    //Create a heightmap using the DiamondSquare algorithm
	val hm = DiamondSquare(8,0.1f,0.45f,0.425f)
	hm.scale(0.0f,maxHeight)
	
	//Create a mesh from the heightmap
    val mesh = MeshShapes.TriangleMesh(hm,2.0f)

    //calculate colors based on the height of the height of the mesh
    val colArray = new Array[Float](hm.length * hm.length * 3)
    val vertArray = mesh(ArrayType.Vertex).getDataArray

    val b0 = 0.0f
    val b1 = maxHeight * 0.2f
    val b2 = maxHeight * 0.4f
    val b3 = maxHeight * 0.6f
    val b4 = maxHeight * 0.8f
    val b5 = maxHeight
    
    for(x <- 0 until hm.length;
        y <- 0 until hm.length){
      
      val curIndex = (x * hm.length + y) * 3
    	
      val fY = vertArray(curIndex + 1)
    
      var cR = 0.0f
      var cG = 0.0f
      var cB = 0.0f
      
      if(fY <= b1)
        { cR=0.5f; cG=0.5f; cB=1.0f}
      else if(fY<=b2) 
        { cR=0.5f; cG=1.0f; cB=0.5f}
      else if(fY<=b3) 
        { cR=1.0f; cG=1.0f; cB=0.5f}
      else if(fY<=b4) 
        { cR=1.0f; cG=0.5f; cB=0.5f}
      else
        { cR=1.0f; cG=1.0f; cB=1.0f}  
      
      colArray(curIndex) = cR
      colArray(curIndex+1) = cG
      colArray(curIndex+2) = cB
    }
    
    //Add the color vertex to the mesh
    mesh.replaceVertData(ArrayType.Color,3,colArray)
    
    //Register the mesh to be rendered using VBOs
	meshId = util.meshRenderer.register(gl,mesh,UpdateFrequency.Rarely )
  }
  
  override def updateLogic(seconds:Float){
    this.dt = seconds

    //Calculate the rolling average fps over the past 25 frames
    fpsAvg = ((25.0f * fpsAvg) + seconds) / 26.0f
    
    //update rotation variable to animate the spinning mesh
    dRot = dRot + dt * 10.0f

  }
  
  override def renderScene(drawable:GLAutoDrawable){
    val gl = drawable.getGL.getGL2
    import gl._
    
    //Clear the depth and color buffers so that we have a 
    //blank screen to render to
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)
    glEnable(GL_LIGHTING)
    
    //Reset the current modelview matrix
    glLoadIdentity();
    
    //Translate the mesh 2 units away from the camera
    glTranslatef(0.0f,0.0f,-2.0f)

    //Rotate the mesh so that we can get a good view of it.
    glRotatef(50.0f,1.0f,0.0f,0.0f)
    glRotatef(dRot,0.0f,1.0f,0.0f)
    glTranslatef(0.0f,-.5f,0.0f)
    
    //Render the mesh
    util.meshRenderer.render(gl,meshId)

    //Render the fps to the screen
    text beginRendering(drawable.getWidth, drawable.getHeight)
    text setColor(1.0f, 1.0f, 1.0f, 1.0f);
    text draw("" + 1.0f/dt,0,0);
    text draw("" + 1.0f/fpsAvg,0,16);
    text endRendering
      
    glFlush
  }
}